




package com.griaule.fingerprintsdk.appletsample;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


import java.io.InputStream;
import java.sql.SQLException;

import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;



import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;

import com.griaule.grfingerjava.FingerprintImage;
import com.griaule.grfingerjava.GrFingerJava;
import com.griaule.grfingerjava.GrFingerJavaException;
import com.griaule.grfingerjava.IFingerEventListener;
import com.griaule.grfingerjava.IImageEventListener;
import com.griaule.grfingerjava.IStatusEventListener;
import com.griaule.grfingerjava.MatchingContext;
import com.griaule.grfingerjava.Template;
import finger.ConexaoBD;
import finger.FingerPrint;
import java.io.ByteArrayInputStream;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.UUID;


/**
 * Class responsible for handling Fingerprint SDK.
 *
 * It handles fingerprint loading/capturing, template extraction,
 * fingerprint image saving and storing/retrieving from template base.
 */
public class Util implements IStatusEventListener, IImageEventListener, IFingerEventListener {

    /** Fingerprint SDK context used for capture / extraction / matching of fingerprints. */
    private MatchingContext fingerprintSDK;
    /** User interface, where logs, images and other things will be sent. */
    private FormMain ui;

    /** Sets if template must be automatically extracted after capture. */
    private boolean autoExtract = true;
    /** Sets if template must be automatically identified after capture.
     It's only effective when *autoExtract == true) */
    private boolean autoIdentify = false;

    private boolean autoEnroll = false;

    /** The last fingerprint image acquired. */
    private FingerprintImage fingerprint;
    /** The template extracted from the last acquired image. */
    private Template template;

    private FingerPrint fingerApplet;

    private String matricula;
    private String fingerPos;

    private String mensagem;


    /**
     * Creates a new Util to be used by the specified Main Form.
     *
     * Initializes fingerprint capture and database connection.
     */
    public Util(FormMain ui) {
        this.ui = ui;

        //Initializes DB connection
        initDB();
        //Initializes Fingerprint SDK and enables fingerprint capture.
        initFingerprintSDK();
    }

    public Util(FingerPrint fingerApplet){
        this.fingerApplet = fingerApplet;
        //Initializes DB connection
        initDB();
        //Initializes Fingerprint SDK and enables fingerprint capture.
        initFingerprintSDK();
    }

    /**
     * Stops fingerprint capture and closes the database connection.
     */
    public void destroy() {
        destroyFingerprintSDK();
        destroyDB();
    }

    /**
     * Initializes Fingerprint SDK and enables fingerprint capture.
     */
    private void initFingerprintSDK() {
        try {
            // install Fingerprint SDK files in a temporary directory
            AppletInstaller.install(getClass().getResource("/FingerprintSDKLibs.zip"));

            fingerprintSDK = new MatchingContext();
            //Starts fingerprint capture.
            GrFingerJava.initializeCapture(this);

            System.out.println("**Sistema Biometrico SISRU - iniciado com sucesso**");

        } catch (Exception e) {
            //If any error ocurred while initializing Fingerprint SDK,
            //writes the error to log
            System.out.println(e.getMessage());
        }
    }

    /**
     * Stops fingerprint capture.
     */
    private void destroyFingerprintSDK() {
        try {
            GrFingerJava.finalizeCapture();
        } catch (GrFingerJavaException e) {
            e.printStackTrace();
        }
    }


    /**
     * This function is called every time a fingerprint reader is plugged.
     *
     * @see griaule.grFinger.StatusCallBack#onPlug(java.lang.String)
     */
    public void onSensorPlug(String idSensor) {
        //Logs the sensor has been pluged.
        System.out.println("Sensor: "+idSensor+" Conectado.");
        try {
            //Start capturing from plugged sensor.
            GrFingerJava.startCapture(idSensor, this, this);
        } catch (GrFingerJavaException e) {
            //write error to log
            System.out.println(e.getMessage());
        }
    }

    /**
     * This function is called every time a fingerprint reader is unplugged.
     *
     * @see griaule.grFinger.StatusCallBack#onUnplug(java.lang.String)
     */
    public void onSensorUnplug(String idSensor) {
        //Logs the sensor has been unpluged.
        System.out.println("Sensor: "+idSensor+" Desconectado.");
        try {
            GrFingerJava.stopCapture(idSensor);
        } catch (GrFingerJavaException e) {
            System.out.println(e.getMessage());
        }
    }

    /**
     * This function is called every time a fingerfrint image is captured.
     *
     * @see griaule.grFinger.ImageCallBack#onImage(java.lang.String, griaule.grFinger.FingerprintImage)
     */
    //int flag_enroll=0;
    int flag_matricula;
    //int super_flag = 0;
    Template direito = new Template();
    Template esquerdo = new Template();
    //Template finger = new Template();
    @Override
    public void onImageAcquired(String idSensor, FingerprintImage fingerprint) {
        //Logs that an Image Event occurred.
        System.out.println("Sensor: "+idSensor+". Event: Image Captured.");

        //Stores the captured Fingerprint Image
        this.fingerprint=fingerprint;
        
        //If auto-extraction is enabled, let's extract the image.
        if (autoExtract) {
            extract();
            System.out.println("autoEnroll: "+autoEnroll);
            if(autoEnroll) {
                enroll();
            }
            //If auto-Identify is also enabled, let's identify it.
            if (autoIdentify) {
                identify();
            }
        }
    }

    /**
     * This Function is called every time a finger is placed on sensor.
     *
     * @see griaule.grFinger.FingerCallBack#onFingerDown(java.lang.String)
     */
    public void onFingerDown(String idSensor) {
        // Just signals that a finger event ocurred.
       // ui.writeLog("Sensor: "+idSensor+" Digital processada.");

    }

    /**
     * This Function is called every time a finger is removed from sensor.
     *
     * @see griaule.grFinger.FingerCallBack#onFingerUp(java.lang.String)
     */
    public void onFingerUp(String idSensor) {
        // Just signals that a finger event ocurred.
       // ui.writeLog("Sensor: "+idSensor+" Digital removida.");

    }


    /**
     * Sets the colors used to paint templates.
     */
    public void setBiometricDisplayColors(
            Color minutiaeColor, Color minutiaeMatchColor,
            Color segmentColor, Color segmentMatchColor,
            Color directionColor, Color directionMatchColor)
    {
        try {
            // set new colors for BiometricDisplay
            GrFingerJava.setBiometricImageColors(
                    minutiaeColor,  minutiaeMatchColor,
                    segmentColor,   segmentMatchColor,
                    directionColor, directionMatchColor);

        } catch (GrFingerJavaException e) {
            //write error to log
            ui.writeLog(e.getMessage());
        }
    }

    /**
     * Returns a String containing information about the version of Fingerprint SDK being used.
     *
     * For instace:
     *      --------------------------------
     *      Fingerprint SDK version 5.0.
     *      The license type is 'Identification'.
     *      --------------------------------
     */
    public String getFingerprintSDKVersion() {
        try {
            return
                "Fingerprint SDK version " + GrFingerJava.getMajorVersion() + "." + GrFingerJava.getMinorVersion() + "\n" +
                "License type is '" + (GrFingerJava.getLicenseType() == GrFingerJava.GRFINGER_JAVA_FULL ? "Identification" : "Verification") + "'.";

        } catch (GrFingerJavaException e) {
            return null;
        }
    }

    /**
     * returns the current fingerprint image, without any biometric
     * information.
     */
    public BufferedImage getFingerprint() {
        return this.fingerprint;
    }

    /**
     * Saves the fingerprint image to a file using an ImageWriterSpi.
     * See ImageIO API.
     */
    public void saveToFile(File file, ImageWriterSpi spi) {
        try {
            //Creates a image writer.
            ImageWriter writer = spi.createWriterInstance();
            ImageOutputStream output = ImageIO.createImageOutputStream(file);
            writer.setOutput(output);

            //Writes the image.
            writer.write(fingerprint);

            //Closes the stream.
            output.close();
            writer.dispose();
        } catch (IOException e) {
            // write error to log
            ui.writeLog(e.toString());
        }

    }

    /**
     * Loads a fingerprint image from file using an ImageReaderSpi.
     * See ImageIO API.
     */
    public void loadFile(File file, int resolution, ImageReaderSpi spi) {
        try {
            //Creates a image reader.
            ImageReader reader = spi.createReaderInstance();
            ImageInputStream input = ImageIO.createImageInputStream(file);
            reader.setInput(input);
            //Reads the image.
            BufferedImage img = reader.read(0);
            //Close the stream
            reader.dispose();
            input.close();
            // creates and processes the fingerprint image
            onImageAcquired("File", new FingerprintImage(img, resolution));
        } catch (Exception e) {
            // write error to log
            ui.writeLog(e.toString());
        }
    }

    /**
     * Sets the parameters used for identifications / verifications.
     */
    public void setParameters(int identifyThreshold, int identifyRotationTolerance, int verifyThreshold, int verifyRotationTolorance) {
        try {
            fingerprintSDK.setIdentificationThreshold(identifyThreshold);
            fingerprintSDK.setIdentificationRotationTolerance(identifyRotationTolerance);
            fingerprintSDK.setVerificationRotationTolerance(verifyRotationTolorance);
            fingerprintSDK.setVerificationThreshold(verifyThreshold);

        } catch (GrFingerJavaException e) {
            //write error to log
            ui.writeLog(e.getMessage());
        }
    }

    /**
     * Returns the current verification threshold.
     */
    public int getVerifyThreshold() {
        try {
            //Try to get the parameters from Fingerprint SDK.
            return fingerprintSDK.getVerificationThreshold();
        } catch (GrFingerJavaException e) {
            //If fails to load the parameters, writes error to log and returns 0
            ui.writeLog(e.getMessage());
            return 0;
        }
    }

    /**
     * Returns the current rotation tolerance on verifications.
     */
    public int getVerifyRotationTolerance() {
        try {
            //Try to get the parameters from Fingerprint SDK.
            return fingerprintSDK.getVerificationRotationTolerance();
        } catch (GrFingerJavaException e) {
            //If fails to load the parameters, writes error to log and returns 0
            ui.writeLog(e.getMessage());
            return 0;
        }
    }

    /**
     * Returns the current identification threshold.
     */
    public int getIdentifyThreshold() {
        try {
            //Try to get the parameters from Fingerprint SDK.
            return fingerprintSDK.getIdentificationThreshold();
        } catch (GrFingerJavaException e) {
            //If fails to load the parameters, writes error to log and returns 0
            ui.writeLog(e.getMessage());
            return 0;
        }
    }

    /**
     * Returns the current rotation tolerance on identification.
     */
    public int getIdentifyRotationTolerance() {
        try {
            //Try to get the parameters from Fingerprint SDK.
            return fingerprintSDK.getIdentificationRotationTolerance();
        } catch (GrFingerJavaException e) {
            //If fails to load the parameters, writes error to log and returns 0
            ui.writeLog(e.getMessage());
            return 0;
        }
    }

    /**
     * Enables / Disables automatic fingerprint identification after
     * capture.
     *
     * As identification must be done after template extraction, this property
     * will only be effective if autoExtract if set to true.
     */
    public void setAutoIdentify(boolean state) {
        autoIdentify = state;
    }

    /**
     * Enables / Disables automatic fingerprint extraction after
     * capture.
     */
    public void setAutoExtract(boolean state) {
        autoExtract = state;
    }









    /**The applet version of this sample stores all fingerprints in memory.*/
    private List database;


    /**
     * Initializes the database.
     */
    private void initDB() {
        //On the applet sample, the database is stored on a in-memory list.
        database = new ArrayList();
    }

    /**
     * Closes the connection to the database and frees any resources used.
     */
    private void destroyDB() {
        //On the applet sample, no database connection is used.
    }

    public void enroll() {
        if(template!=null && template.getQuality()>=Template.MEDIUM_QUALITY){ //Cadastra no banco
            try {
                ConexaoBD con = new ConexaoBD();
                con.open();
                PreparedStatement pStmt = null;
                if(this.fingerPos.equals("Esquerdo")){
                    pStmt = con.getConexao().prepareStatement("update aluno set digital_esq = ? where id = (select aluno_id from curso_aluno where matr_aluno = ?)");
                } else {
                    pStmt = con.getConexao().prepareStatement("update aluno set digital_dir = ? where id = (select aluno_id from curso_aluno where matr_aluno = ?)");
                }
                pStmt.setBinaryStream(1,new ByteArrayInputStream(template.getData()),template.getData().length);
                pStmt.setString(2,matricula);
                pStmt.executeUpdate();
                con.close();
                resetTemplate();
                //JOptionPane.showMessageDialog(null, "Digital Cadastrada com Sucesso!");
                this.mensagem = "true";
            } catch (ClassNotFoundException ex) {
                System.out.println(ex.getMessage());
                //JOptionPane.showMessageDialog(null, "Erro: "+ex.getMessage());
                this.mensagem = "Erro: "+ex.getMessage();
            } catch (SQLException ex) {
                System.out.println(ex.getMessage());
                //JOptionPane.showMessageDialog(null, "Erro: "+ex.getMessage());
                this.mensagem = "Erro: "+ex.getMessage();
            }
        } else {    //Para digital de baixa qualidade
            //JOptionPane.showMessageDialog(null, "Leitura de baixa qualidade.\nEfetue a leitura da digital novamente!");
            this.mensagem = "Leitura de baixa qualidade.\nEfetue a leitura da digital novamente!";
        }
        autoEnroll = false;
    }

    /**
     * Check current fingerprint against another one in the DB.
     */
    public void verify(int id) {
        Connection con;
        
         try
         {

            String url = "jdbc:postgresql://localhost:5432/alunos";
            String usuario = "postgres";
            Class.forName("org.postgresql.Driver");
            con = DriverManager.getConnection(url, usuario,usuario);
            System.out.println("Conex�o realizada com sucesso.");
            Statement sq_stmt = con.createStatement();
            String sql_str = "SELECT * FROM teste";
            System.out.println("dando select");

            ResultSet rs = sq_stmt.executeQuery(sql_str);
            while (rs.next()) {
                //int fulano = rs.getInt("matricula");
                Template digital = new Template();
                List bla = null;
                InputStream stream = rs.getBinaryStream("digital");
                bla.add(stream);
                digital = (Template) bla.get(bla.size()-1);
                               
                boolean matched = fingerprintSDK.verify(template,digital);
				  //Criar um novo template
		if (matched){
                    //displays minutiae/segments/directions that matched.
                    ui.showImage(GrFingerJava.getBiometricImage(template, fingerprint, fingerprintSDK));
                    //Notifies the templates did match.
                    ui.writeLog("Compativel - pontua��o = " + fingerprintSDK.getScore() + ".");
                } else {
                    //Notifies the templates did not match.
                    ui.writeLog("N�o compativel - pontua��o = " + fingerprintSDK.getScore() + ".");
                }
            }
        } catch(Exception e){

        }
    }

    /**
     * Identifies the current fingerprint on the DB.
     */
    public Boolean identify() {
        if(template!=null && template.getQuality()>=Template.MEDIUM_QUALITY){ //Cadastra no banco
            Template templateEsqBD = null;
            Template templateDirBD = null;
            try {
                ConexaoBD con = new ConexaoBD();
                con.open();
                PreparedStatement pStmt = null;
                
                pStmt = con.getConexao().prepareStatement("select t1.digital_esq, t1.digital_dir, t1.id as aluno_id, t2.id as curso_aluno_id, t2.forma_evasao from aluno t1, curso_aluno t2 where t1.id = t2.aluno_id and t2.matr_aluno = ?");
                pStmt.setString(1,matricula);
                ResultSet rs = pStmt.executeQuery();
                Long alunoId = null;
                Long cursoAlunoId = null;
                String formaEvasao = null;
                while (rs.next()) {
                    byte byteEsqBD[] = rs.getBytes(1);
                    if(byteEsqBD!=null) {
                        templateEsqBD = new Template(byteEsqBD);
                    }
                    byte byteDirBD[] = rs.getBytes(2);
                    if(byteDirBD!=null) {
                        templateDirBD = new Template(byteDirBD);
                    }
                    alunoId = rs.getLong(3);
                    cursoAlunoId = rs.getLong(4);
                    formaEvasao = rs.getString(5);
                }
                
                Boolean matched = false;
                if(templateEsqBD==null && templateDirBD==null){
                    matched = false;
                } else if (templateEsqBD!=null && fingerprintSDK.verify(template, templateEsqBD)) {
                    matched = true;
                } else if (templateDirBD!=null && fingerprintSDK.verify(template, templateDirBD)) {
                    matched = true;
                }
                
                if (matched) {
                    System.out.println("Digital reconhecida");

                    //Checa se o aluno esta ativo
                    System.out.println("Checa se o aluno esta ativo");
                    if(!formaEvasao.equals("SEM EVASÃO")) {
                        this.mensagem = "Sem direito a refeição. Aluno com situação "+formaEvasao+".";
                        return false;
                    }
                    
                    // Seleciona o tipo de refeicao pela hora
                    System.out.println("Seleciona tipo refeicao pelo horario");
                    pStmt = con.getConexao().prepareStatement("select id from tipo_alimentacao where to_char(inicio,'hh24:mi:ss') <= to_char(now(),'hh24:mi:ss') and to_char(fim,'hh24:mi:ss') >= to_char(now(),'hh24:mi:ss')");
                    rs = pStmt.executeQuery();
                    String tipoAlimentacaoId = null;
                    while (rs.next()) {
                        tipoAlimentacaoId = rs.getString("id");
                    }
                    if(tipoAlimentacaoId==null){
                        this.mensagem = "Nenhuma refeição encontrada para o horário atual.";
                        return false;
                    }
                    
                    // Checa se o aluno ja usufruiu este tipo de refeicao na data de hoje
                    System.out.println("Checa se o aluno ja usufruiu este tipo de refeicao na data de hoje");
                    pStmt = con.getConexao().prepareStatement("select t1.id, t2.descricao, to_char(t1.date_created,'dd/mm/yyyy às hh24:mi:ss') from consumo t1, tipo_alimentacao t2 where t1.tipo_alimentacao_id = t2.id and t1.aluno_id = ? and t1.tipo_alimentacao_id = ? and to_char(t1.date_created,'dd/mm/yyyy') = to_char(now(),'dd/mm/yyyy')");
                    pStmt.setLong(1,alunoId);
                    pStmt.setString(2,tipoAlimentacaoId);
                    rs = pStmt.executeQuery();
                    String msgLimiteRefeicao = null;
                    while (rs.next()) {
                        msgLimiteRefeicao = "Consumo anterior registrado: "+rs.getString(2)+" em "+rs.getString(3);
                    }
                    if(msgLimiteRefeicao!=null){
                        this.mensagem = "Aluno só pode usufruir um tipo de refeição por dia. \n"+msgLimiteRefeicao;
                        return false;
                    }

                    System.out.println("Registra consumo");
                    pStmt = con.getConexao().prepareStatement("insert into consumo (id, version, aluno_id, curso_aluno_id, date_created, last_updated, tipo_alimentacao_id) values (?,?,?,?,now(),now(),?)");
                    pStmt.setString(1,UUID.randomUUID().toString());
                    pStmt.setLong(2,0);
                    pStmt.setLong(3,alunoId); //aluno_id
                    pStmt.setLong(4,cursoAlunoId); //curso_aluno_id
                    pStmt.setString(5,tipoAlimentacaoId); //tipo_alimentacao_id
                    pStmt.executeUpdate();
                    this.mensagem = "true";
                    return true;
                } else {
                    this.mensagem = "Digital não reconhecida!";
                    System.out.println("Digital nao reconhecida");
                }
                //System.out.println(UUID.randomUUID().toString());
                
                con.close();
            } catch (ClassNotFoundException ex) {
                System.out.println(ex.getMessage());
                this.mensagem = ex.getMessage();
            } catch (SQLException ex) {
                System.out.println(ex.getMessage());                
                this.mensagem = ex.getMessage();
            } catch (GrFingerJavaException ex) {
                System.out.println(ex.getMessage());
                this.mensagem = ex.getMessage();
            } catch (IllegalArgumentException ex) {
                System.out.println(ex.getMessage());
                this.mensagem = ex.getMessage();
            }
        } else {    //Para digital de baixa qualidade
            //JOptionPane.showMessageDialog(null, "Leitura de baixa qualidade.\nEfetue a leitura da digital novamente!");
            this.mensagem = "Leitura de baixa qualidade.\nEfetue a leitura da digital novamente!";
        }
        return false;
    }


   
    public void extract() {

        try {
            //Extracts a template from the current fingerprint image.
            template = fingerprintSDK.extract(fingerprint);

            //Notifies it has been extracted and the quality of the extraction
            String msg = "";
            //write template quality to log
            switch (template.getQuality()){
                case Template.HIGH_QUALITY:     msg +="Imagem com qualidade maxima.";   break;
                case Template.MEDIUM_QUALITY:   msg +="Imagem com qualidade media."; break;
                case Template.LOW_QUALITY:      msg +="Imagem com qualidade baixa.";    break;
            }
            System.out.println(msg);

            //Notifies the UI that template operations can be enabled.
            //ui.enableTemplate();
            //display minutiae/segments/directions into image
            //ui.showImage(GrFingerJava.getBiometricImage(template,fingerprint));

        } catch (GrFingerJavaException e) {
            //write error to log
            System.out.println(e.getMessage());
        }

    }

    /**
     * Removes all templates from the database.
     */
    public void clearDB() {
        database.clear();
        ui.writeLog("Database is clear...");
    }

    public Template getTemplate(){
        return this.template;
    }

    public void resetTemplate(){
        this.template = null;
    }

    public void setMatricula(String matricula){
        this.matricula = matricula;
    }

    public String getMensagem(){
        return mensagem;
    }

    public void setMensagem(String mensagem){
        this.mensagem = mensagem;
    }

    public void setAutoEnroll(boolean autoEnroll){
        this.autoEnroll = autoEnroll;
    }

    public void setFingerPos(String fingerPos){
        this.fingerPos = fingerPos;
    }
}
